<!-- 
	[一个用来装表单的dialog]
	通常用于table数据管理中的新增、编辑场景

	- 自动根据 props.formdata.id 判断是新增还是编辑场景
 -->

<script setup lang="ts">
import { ref, reactive, computed, useAttrs, watch, type PropType } from 'vue'
import { cloneDeep, assign } from 'lodash-es'
import { useWindowSize } from '@vueuse/core'

const props = defineProps({
	/** 模型名，会自动拼接到title上 */
	name: {
		type: String,
	},
	/** 表单数据 */
	formdata: {
		type: Object,
		default: () => ({}),
	},
	/** 标题，若不设置会自动判断 */
	title: {
		type: String,
	},
	/** 宽度，若不设置会采用智能宽度 */
	width: {
		type: [String, Number],
	},
	/**
	 * 智能宽度
	 * 单位px，优先级低于width。设置为一个固定宽度，当屏幕尺寸小于该宽度时，自动切换宽度为100vw
	 */
	smartWidth: {
		type: Number,
		default: 600,
	},
	/** 是否显示，若不设置内部自己处理，设置后改为受控模式 */
	visible: {
		type: Boolean,
		default: false,
	},
	/** 点击提交时触发 */
	onClickSubmit: {
		type: Function as PropType<(formdata: typeof props.formdata) => Promise<any>>,
	},
})

const emit = defineEmits({
	/** 更新formdata */
	'update:formdata': null,
	/** 更新可见状态 */
	'update:visible': null,
	/** 取消 */
	cancel: null,
})

const attrs = useAttrs()

const screen = useWindowSize()

const showTitle = computed(() => props.title ?? `${props.formdata?.id ? '编辑' : '新增'}${props.name}`)
const showWidth = computed(() => {
	if (typeof props.width !== 'undefined') return props.width
	if (typeof props.smartWidth !== 'undefined')
		return screen.width.value >= props.smartWidth ? `${props.smartWidth}px` : '98%'
	return undefined
})

const my_visible = ref(props.visible)
const submit_loading = ref(false)
const init_formdata = reactive(props.formdata)

const open = (row?, onoff = true) => {
	emit('update:formdata', row ? cloneDeep(assign({}, props.formdata, cloneDeep(row))) : cloneDeep(init_formdata))
	my_visible.value = onoff
}

const onEditFormSubmit = () => {
	if (props.onClickSubmit) {
		submit_loading.value = true
		props
			.onClickSubmit(cloneDeep(props.formdata))
			.then(() => open(undefined, false))
			.catch(() => {})
			.finally(() => (submit_loading.value = false))
	}
}

watch(
	() => my_visible.value,
	(val) => emit('update:visible', val)
)
watch(
	() => props.visible,
	(val) => {
		if (val != my_visible.value) my_visible.value = val
	}
)

defineExpose({ open })
</script>

<template>
	<el-dialog v-bind="attrs" v-model="my_visible" :title="showTitle" :width="showWidth">
		<slot></slot>
		<template #footer>
			<slot name="footer">
				<div class="flex-box justify-end space-x-2">
					<el-button @click="$emit('cancel'), (my_visible = false)">取 消</el-button>
					<el-button type="primary" :loading="submit_loading" @click="onEditFormSubmit">保 存</el-button>
				</div>
			</slot>
		</template>
	</el-dialog>
</template>
